package com.xjh.him.netty;

import com.xjh.him.netty.codec.*;
import com.xjh.him.netty.handler.BaseHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

@Slf4j
public class NettyClient {
    private InetSocketAddress address;
    private NioEventLoopGroup workerGroup;
    private Bootstrap bootstrap;
    private ChannelInboundHandler respHandler;
    private ChannelFuture future;

    public static void main(String[] args) {
        InetSocketAddress socketAddress = new InetSocketAddress(
                "192.168.1.12",8001
        );
        NettyClient nettyClient = new NettyClient(socketAddress, new BaseHandler());
        nettyClient.connect();
        nettyClient.send(Packet.create(Command.USER_ID_REQ, 1L));
    }

    public NettyClient(InetSocketAddress address, ChannelInboundHandler respHandler) {
        this.address = address;
        this.respHandler = respHandler;
        workerGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
    }

    public void connect() {
        bootstrap.group(workerGroup)
            .channel(Epoll.isAvailable() ? EpollSocketChannel.class :
                    NioSocketChannel.class)
            .handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel channel) {
                    ChannelPipeline pipeline = channel.pipeline();

                    pipeline.addLast("Client LengthFieldDecoder", new LengthFieldDecoder());
                    pipeline.addLast("Client Decoder", new MsgDecoder());
                    pipeline.addLast("Client ResponseHandler", respHandler);
                    pipeline.addLast("Client Encoder", new MsgEncoder());
                }
            });
        future = bootstrap.connect(address);
        future.addListener((ChannelFutureListener) f -> {
            if (f.isSuccess()) {
                log.info("client connect {} success.", address);
            }else {
                f.channel().pipeline().fireChannelInactive();
                log.info("client connect {} failed. {}", address, f.cause().getMessage());
            }
        });
    }

    public ChannelFuture send(Object msg) {
        return future.channel().writeAndFlush(msg);
    }
}
